<?php

namespace App\Library\Service;

use App\Library\Logic\KefuLogic;
use App\Library\Logic\MessageListLogic;
use App\Library\Logic\MessageLogic;
use App\Library\Logic\ShopOrderGoodsLogic;
use App\Library\Logic\ShopOrderLogic;
use App\Library\Logic\ShopProductLogic;
use App\Library\Logic\ShopProductSpecsLogic;
use App\Library\Requests\Base\BasePageRequest;
use App\Library\Requests\Base\IdRequest;
use App\Library\Requests\Message\MessageAddObjectRequest;
use App\Library\Requests\Message\MessageAddRequest;
use App\Library\Requests\Message\MessageNewRequest;
use App\Library\Requests\Message\MessagePageRequest;
use App\Library\Requests\Message\MessageReadRequest;
use App\Library\Requests\Message\MessageUserInfoRequest;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\JsonResponse;

class MessageService extends BaseService
{
    /**
     * @param MessageLogic $logic
     */
    public function __construct(MessageLogic $logic)
    {
        $this->logic = $logic;
    }

    /**
     * 分页
     * @param MessagePageRequest $request
     * @return JsonResponse
     */
    public function paging(MessagePageRequest $request): JsonResponse
    {
        return success($this->logic->paging($request));
    }

    /**
     * 最新
     * @param MessageNewRequest $request
     * @return JsonResponse
     */
    public function new(MessageNewRequest $request): JsonResponse
    {
        return success($this->logic->new($request));
    }

    /**
     * add
     * @param MessageAddRequest $request
     * @return JsonResponse
     */
    public function add(MessageAddRequest $request): JsonResponse
    {
        if (is_null($request->text)) $text = null;
        else $text = htmlspecialchars(strip_tags(trim($request->text)));
        if (empty($text) && is_null($request->fileId)) return failMessage('内容不能为空');
        $text = is_null($request->fileId) ? $request->text : '[图片]';
        $k = 'kf:' . USERID;
        $userId = cache()->has($k) ? cache($k)['sellerId'] : USERID;
        MessageListLogic::add($userId, $request->acceptId, $text, $request->buyer);
        $this->reception($request->buyer, $request->acceptId, $text);
        return success($this->logic->insertForModel([
            'sendId' => $userId,
            'acceptId' => $request->acceptId,
            'content' => $request->text,
            'fileId' => $request->fileId,
            'kefuId' => cache()->has('kfStatus:' . USERID) ? USERID : 0,
        ])->id);
    }

    /**
     * addObject
     * @param MessageAddObjectRequest $request
     * @return JsonResponse
     */
    public function addObject(MessageAddObjectRequest $request): JsonResponse
    {
        $extend = ['serialNumber' => $request->serialNumber];
        $ids = [USERID, $request->acceptId];
        if ($request->objectType === 'shopProduct') {
            $shopProduct = ShopProductLogic::findBySerialNumber($request);
            if (is_null($shopProduct)) return fail(433);
            else if (!in_array($shopProduct->user_id, array_merge($ids, [MAINID]))) return fail(433);
            $text = '[商品]';
            $objectId = $shopProduct->product_id;
            $extend = array_merge($extend, [
                'title' => $shopProduct->product_name,
                'fileId' => $shopProduct->product_avatar,
                'price' => ShopProductSpecsLogic::minPrice($shopProduct),
            ]);
        } else if ($request->objectType === 'shopOrder') {
            $shopOrder = ShopOrderLogic::findBySerialNumber($request);
            if (is_null($shopOrder)) return fail(433);
            else if (!in_array($shopOrder->ext->user_id, $ids) && !in_array($shopOrder->ext->seller_id, $ids)) {
                return fail(433);
            }
            $text = '[商品订单]';
            $objectId = $shopOrder->order_id;
            $extend['status'] = $shopOrder->ext->status;
            $extend = array_merge($extend, ['goods' => $shopOrder->messageGoods]);
        } else return fail(433);
        $k = 'kf:' . USERID;
        $userId = cache()->has($k) ? cache($k)['sellerId'] : USERID;
        MessageListLogic::add($userId, $request->acceptId, $text, $request->buyer);
        $this->reception($request->buyer, $request->acceptId, $text);
        return success($this->logic->insertForModel([
            'sendId' => $userId,
            'acceptId' => $request->acceptId,
            'objectType' => $request->objectType,
            'objectId' => $objectId,
            'extend' => $extend,
        ])->id);
    }

    /**
     * userInfo
     * @param MessageUserInfoRequest $request
     * @return JsonResponse
     */
    public function userInfo(MessageUserInfoRequest $request): JsonResponse
    {
        $k = 'kf:' . USERID;
        if (cache()->has($k)) {
            $user = $this->intersect($request->id);
            $seller = $this->intersect(cache($k)['sellerId']);
            $k = 'reception:' . $request->id;
            if (cache()->has($k)) $kefu = (int)cache($k);
            else $kefu = null;
            $send = !($kefu === null || $kefu !== USERID);
        } else {
            $userId = $request->buyer ? USERID : $request->id;
            $user = $this->intersect($userId);
            $seller = $this->intersect($request->buyer ? $request->id : USERID);
            $k = 'reception:' . $userId;
            if (cache()->has($k)) $kefu = (int)cache($k);
            else $kefu = null;
            $send = $request->buyer || $kefu === null || $kefu === USERID;
        }
        return success(compact('seller', 'user', 'kefu', 'send'));
    }

    /**
     * messageList
     * @param BasePageRequest $request
     * @return JsonResponse
     */
    public function messageList(BasePageRequest $request): JsonResponse
    {
        return success(MessageListLogic::messageList($request));
    }

    /**
     * read
     * @param MessageReadRequest $request
     * @return JsonResponse
     *
     */
    public function read(MessageReadRequest $request): JsonResponse
    {
        $k = 'kf:' . USERID;
        $userId = cache()->has($k) ? cache($k)['sellerId'] : USERID;
        MessageListLogic::query()->where('status', 0)->where('accept_id', $userId)->update(['status' => 1]);
        if (cache()->has($k)) {
            $userId = $request->acceptId === $userId ? $request->sendId : $request->acceptId;
            cache()->forget(implode(':', ['consultCount', USERID, $userId]));
        }
        return success();
    }

    /**
     * kefu
     * @param IdRequest $request
     * @return JsonResponse
     */
    public function kefu(IdRequest $request): JsonResponse
    {
        $arr = [];
        foreach (redis('keys', 'kf:*') as $v) {
            $cache = cache($v);
            if ($cache['sellerId'] !== $request->id) continue;
            $arr[str_replace('kf:', '', $v)] = [
                'name' => $cache['name'],
                'fileId' => $cache['fileId'],
            ];
        }
        return success($arr);
    }

    /**
     * count
     * @return JsonResponse
     */
    public function count(): JsonResponse
    {
        return success(MessageListLogic::count());
    }

    /**
     * reception
     * @param bool $buyer
     * @param int $acceptId
     * @param string $text
     * @return void
     */
    private function reception(bool $buyer, int $acceptId, string $text): void
    {
        if (time() > PHP_INT_MAX) return;
        else if ($buyer) {//买家发送消息
            $k = 'reception:' . USERID;
            if (cache()->has($k)) {//有客服接待
                $this->consult((int)cache($k), USERID, $text, true);
                return;
            }
            $array = KefuLogic::online($acceptId);
            if (empty($array)) return;
            $reception = $array[array_rand($array)];
            cache([$k => $reception]);
            $this->consult((int)$reception, USERID, $text, true);
        } else {//卖家/客服发送消息
            if (!cache()->has('kf:' . USERID)) return;
            $k = 'reception:' . $acceptId;
            cache([$k => USERID]);
            $this->consult(USERID, $acceptId, $text, false);
        }
    }

    /**
     * consult
     * @param int $serviceId
     * @param int $userId
     * @param string $text
     * @param bool $buyer
     * @return void
     */
    private function consult(int $serviceId, int $userId, string $text, bool $buyer): void
    {
        redis('zadd', 'consult:' . $serviceId, now()->timestamp . now()->format('u'), $userId);
        cache([implode(':', ['consultInfo', $serviceId, $userId]) => $text]);
        $k = implode(':', ['consultCount', $serviceId, $userId]);
        if ($buyer) cache()->increment($k);
        else cache()->forget($k);
    }

    /**
     * intersect
     * @param int $userId
     * @return array
     */
    private function intersect(int $userId): array
    {
        $flip = ['id', 'mobile', 'nickname', 'avatar'];
        return array_intersect_key(cache('user:' . $userId), array_flip($flip));
    }
}
